#ifndef SEQ_PAIRS_H
#define SEQ_PAIRS_H

#include <string>
#include <istream>
#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include "get_filename.h"
#include "ultoa.h"
#include "open_fstream.h"
#include "progress_indicator.h"
namespace seq_pairs
{
inline std::string column_names()
{
	return "seq1\tseq2";
}
inline std::string column_name_underscores()
{
	return "----\t----";
}
bool skip_header(std::istream& is, std::istringstream& istrm);
// for streams which can be wound back
bool skip_header(std::istream& is);

//bool parse_ids_from_line(const std::string& line, std::string& id1, std::string& id2);
enum ePARSE_IDS{ePARSE_WHOLE_LINE, ePARSE_IDS_ONLY};
bool parse_ids(std::istream& is, std::string& id1, std::string& id2,
			   std::string& comment_line, 
			   const std::string& comment_letters = "#",
			   ePARSE_IDS parse_line = ePARSE_IDS_ONLY);

// get substring which consists of first two ids
bool parse_normalized_ids_sub_string(const std::string& orig, std::string& substr, 
									 const std::string& comment_letters);

//________________________________________________________________________________________

//		read_seq_pair_data_from_file


//			takes CALLBACK function/object. E.g.
// 
//			struct xxx{
// 					void operator()(istream& is, unsigned cnt_line);
// 			}
// 			
// 			where cnt_line is 1 denominated


//________________________________________________________________________________________
template <typename CALLBACK> 
void read_data(	CALLBACK&			callback, 
				const std::string&	file_path,
				std::ostream&		VERBOSE)
{
	std::ifstream ifs;
	std::istream::pos_type file_size = 0;
	std::string file_name = "STDIN";
	bool use_stdin = !file_path.length() || file_path == "STDIN";
	if (!use_stdin)
	{
		file_name = get_filename(file_path);
		file_size = open_fstream(ifs, file_path);
		if (!file_size)
		{
			return;
			//throw std::runtime_error("File size is zero");
		}
	}
	std::istream& is = use_stdin ? std::cin : ifs;

	unsigned dots_size = 200000;
	t_progress_indicator dots(VERBOSE, dots_size);
	dots.use_timer();

	unsigned cnt_line = 1;

	//
	// handle any header
	//
	std::istringstream sstrm;
	if (seq_pairs::skip_header(is, sstrm))
		cnt_line += 2;


	//
	//	read data
	//
	try
	{
		// if file begins with a new line, that will be swallowed silently.
		//  Adjust line count accordingly
		if (sstrm.peek()== EOF)
			++cnt_line;
		--cnt_line;
		while (is.good())
		{
			std::istream& lines = sstrm.good() ? sstrm : is;
			while (lines.good())
			{
				callback(lines, cnt_line + 1);
				++cnt_line;
	
				++dots;
				// check every ten dots 
				if (file_size && dots.value() % (dots_size * 10) == 0)
				{
					std::istream::pos_type file_size_so_far = lines.tellg();
					unsigned dots_needed = unsigned(dots.value() * 1.0 *
								file_size / file_size_so_far);
					dots_needed += dots_size;
					dots.set_limit(dots_needed);
				}
			}
		}

	}
	catch (std::runtime_error& e)
	{
		throw std::runtime_error("Line #" + ultoa(cnt_line + 1) + 
												" is not in the correct format: " + 
								 std::string(e.what()));
	}
	if (!cnt_line)
		throw std::runtime_error("No seq_pair data supplied in [" + file_name + "].");
}

}
#endif //SEQ_PAIRS_H
